﻿using StarryEdge.Core;
using StarryEdge.Core.Models;
using StarryEdge.Core.Plugin;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace StarryEdge.Plugin
{
    internal class Plugin : IPlugin
    {
        private PluginsAssemblyLoadContext _pluginsAssembly;
        private Assembly _assembly;

        public Plugin(PluginInfoModel pluginInfoModel)
        {
            _pluginInfo = pluginInfoModel;
        }

        private PluginInfoModel _pluginInfo;

        public PluginInfoModel PluginInfo
        {
            get { return _pluginInfo; }
        }

        private WeakReference _weakReference;

        public Assembly LoadPlugin(IStarryEdgeLog starryEdgeLog, string assemblyPath = default)
        {
            if (_pluginsAssembly == null)
            {
                _pluginsAssembly = new PluginsAssemblyLoadContext(assemblyPath, starryEdgeLog);
                _weakReference = new WeakReference(_pluginsAssembly);
                using (var fs = File.Open(assemblyPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                {
                    _assembly = _pluginsAssembly.LoadFromStream(fs);
                }
                return _assembly;
            }
            return _assembly;
        }

        public bool UnLoadPlugin(IStarryEdgeLog starryEdgeLog)
        {
            starryEdgeLog?.LogRun($"Start Unloading {_pluginInfo.Name}");
            _pluginsAssembly.Unload();
            int count = 0;
            while (_weakReference.IsAlive)
            {
                count++;
                if (count > 3)
                {
                    starryEdgeLog?.LogRun($"Unloading Error {_pluginInfo.Name}");
                    return false;
                }
                GC.Collect();
                GC.WaitForPendingFinalizers();
                Thread.Sleep(100);
            }
            return true;
        }
    }
}
